perm filename EFSEND.C[11,HE] blob sn#688190 filedate 1982-12-06 generic text, type T, neo UTF8
/* LINTLIBRARY */

/*
 * efsendend.c
 *
 * EFTP Package
 *
 * EfSendEnd -- terminate (normally) an EFTP transfer.
 *
 * Jeffrey Mogul @ Stanford	28-January-1981
 */

#include <eftp.h>
#include <pupconstants.h>
#include <pupstatus.h>

EfSendEnd(Efchan)
struct EftpChan *Efchan;	/* channel on which to end transfer */
{	/* */
	char dummy;		/* instead of a send buffer */
	int retry;
	int inhibit;		/* INVARIANT -- MUST BE 0 or 1 */
	int rstat;
	uchar rpuptype;
	ulong rpupid;
	char msgbuf[100];
	int msgbuflen;

	inhibit = 0;		/* don't inhibit packet sending */

	for (retry=0; retry < Efchan->WaitTime ; retry++) {
		/* attempt to get a packet accross */

		/* the "inhibit" flag is used to avoid re-sending too
		 * quickly if we get a duplicate ACK; the problem is
		 * that an ACK for the packet we just sent may already
		 * be on its way, and we will get into a situation where
		 * every packet is sent twice if we don't watch it.
		 */
		if (!inhibit)	/* test, (and clear later) inhibit */
		    pupwrite(&Efchan->pchan,EFTPEND,Efchan->sequence,
				&dummy,0);
			/* pup id is sequence number */
		inhibit = 0;
		
		/* wait for an ACK */
		rstat = pupread(&Efchan->pchan,msgbuf,&msgbuflen,
				&rpuptype, &rpupid, NULL, NULL);
		if (rstat == BADCKSUM || rstat == TIMEOUT) continue;

		/* got a packet */

		switch ((int)rpuptype) {

		case EFTPACK:
			if (rpupid == Efchan->sequence) {	/* right ack */
				Efchan->sequence++; /* incr. sequence */
				/* now, launch second END to tell receiver
				 * to finish its dally.
				 */
				pupwrite(&Efchan->pchan,EFTPEND,
					Efchan->sequence,&dummy,0);
				return(OK);
				}
			else {	/* got the wrong ack */
				if (rpupid > Efchan->sequence) {
					/* future packet acked ?! */
					return(EFTP_BADACK);
					}
				}
			/* other possibility is repeated ack; ignore it,
			 * but inhibit resending the packet for next
			 * timeout period - another ack may be coming.
			 */
			inhibit++;
			break;	/* effect is to repeat loop & retry */
		
		case EFTPABORT:
			EftpAbortCode = *(ushort *)msgbuf;
			movestring(&msgbuf[2],EftpErrMsg,msgbuflen-2);
			EftpErrMsg[msgbuflen-2] = 0; /* nullterm it */
			return(EFTP_ABORT);
		
		default:	/* we got the wrong packet type! */
			return(EFTP_ERROR);
			}
		}
	/* too many retries */
	return(TIMEOUT);
}